#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

using namespace std;

template<class T>
class blockQueue
{
    static const int Default = 20;
public:
    blockQueue(int maxCap = Default):_maxCapacity(Default)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_c_cond,nullptr);
        pthread_cond_init(&_p_cond,nullptr);
        //high_water = (_maxCapacity*2)/3;
        //low_water = _maxCapacity/3;;

    }

    ~blockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

    void push(const T& data)
    {
        pthread_mutex_lock(&_mutex);
        //数据超过上限，停止生产数据
        //因为判断临界资源条件是否满足，也是在访问临界资源
        while(_q.size() == _maxCapacity) //使用while循环判断，避免伪唤醒的情况
            pthread_cond_wait(&_p_cond,&_mutex); //你是持有锁的，当调用的时候会自动释放锁，当因为唤醒而返回时会重新持有锁
        _q.push(data);

        //数据高于水位线就要喊消费者，消费数据
        //if(_q.size() > high_water) 
        pthread_cond_signal(&_c_cond);

        pthread_mutex_unlock(&_mutex);
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex);
        //没数据就要喊生产者，生产数据
        while(_q.size() == 0) pthread_cond_wait(&_c_cond,&_mutex);
        
        T out = _q.front();
        _q.pop();

        //数据低于就要喊生产者，生产数据
        //if(_q.size() < low_water) 
        pthread_cond_signal(&_p_cond);

        pthread_mutex_unlock(&_mutex);
        return out;
    }

private:
    queue<T> _q;
    int _maxCapacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;

    //int high_water;
    //int low_water;
};